package com.syq.courierDelivery.common.utils;

import com.syq.courierDelivery.entity.vo.Ant;
import com.syq.courierDelivery.entity.vo.Coordinate;
import org.springframework.stereotype.Component;

import java.io.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

public class ACO {
    //定义蚂蚁群
    Ant[] ants;
    int antCount;//蚂蚁的数量
    int [][]distance;//表示城市间距离
    double [][]tao;//信息素矩阵
    int cityCount;//城市数量
    int []bestTour;//求解的最佳路径
    int bestLength;//求的最优解的长度
    /** 初始化函数
     *@param coordinateList 坐标数据
     * @param ids id的集合
     *@param antnum 系统用到蚂蚁的数量
     */
    public void init(List<Map<Long, Coordinate>> coordinateList, List<Long> ids, int antnum) {
        antCount=antnum;
        ants=new Ant[antCount];
        //读取数据
        String[] x;
        String[] y;

        cityCount = coordinateList.size();
        distance = new int[cityCount][cityCount];
        x = new String[cityCount];
        y = new String[cityCount];
        for (int citys = 0; citys < cityCount; citys++) {
            Map<Long, Coordinate> map = coordinateList.get(citys);
            x[citys] = map.get(ids.get(citys)).getX();
            y[citys] = map.get(ids.get(citys)).getY();
        }
        //计算距离矩阵
        for (int city1 = 0; city1 < cityCount - 1; city1++) {
            distance[city1][city1] = 0;
            for (int city2 = city1 + 1; city2 < cityCount; city2++) {
                BigDecimal x1 = new BigDecimal(x[city1]);
                BigDecimal x2 = new BigDecimal(x[city2]);
                BigDecimal y1 = new BigDecimal(y[city1]);
                BigDecimal y2 = new BigDecimal(y[city2]);
                BigDecimal xC = x1.subtract(x2);
                BigDecimal yC = y1.subtract(y2);
                distance[city1][city2] =  BigDecimalCount.sqrt(xC.multiply(xC).add(yC.multiply(yC)),2).intValue();
                distance[city2][city1] = distance[city1][city2];
            }
        }
        distance[cityCount - 1][cityCount - 1] = 0;
        //初始化信息素矩阵
        tao=new double[cityCount][cityCount];
        for(int i=0;i<cityCount;i++)
        {
            for(int j=0;j<cityCount;j++){
                tao[i][j]=1;
            }
        }
        bestLength=Integer.MAX_VALUE;
        bestTour=new int[cityCount+1];
        //随机放置蚂蚁
        for(int i=0;i<antCount;i++){
            ants[i]=new Ant();
            ants[i].RandomSelectCity(cityCount);
        }
    }
    /**
     * ACO的运行过程
     * @param maxgen ACO的最多循环次数
     *
     */
    public void run(int maxgen){
        for(int runtimes=0;runtimes<maxgen;runtimes++){
            //每一只蚂蚁移动的过程
            for(int i=0;i<antCount;i++){
                for(int j=1;j<cityCount;j++){
                    ants[i].selectNextCity(j,tao,distance);
                }
                //计算蚂蚁获得的路径长度
                ants[i].CalTourLength(distance);
                if(ants[i].tourLength<bestLength){
                    //保留最优路径
                    bestLength=ants[i].tourLength;
                    System.out.println("第"+runtimes+"代，发现新的解"+bestLength);
                    for(int j=0;j<cityCount+1;j++)
                        bestTour[j]=ants[i].tour[j];
                }
            }
            //更新信息素矩阵
            UpdateTao();
            //重新随机设置蚂蚁
            for(int i=0;i<antCount;i++){
                ants[i].RandomSelectCity(cityCount);
            }
        }
    }
    /**
     * 更新信息素矩阵
     */
    private void UpdateTao(){
        double rou=0.1;
        //信息素挥发
        for(int i=0;i<cityCount;i++)
            for(int j=0;j<cityCount;j++)
                tao[i][j]=tao[i][j]*(1-rou);
        //信息素更新
        for(int i=0;i<antCount;i++){
            for(int j=0;j<cityCount;j++){
                tao[ants[i].tour[j]][ants[i].tour[j+1]]+=10/ants[i].tourLength;
            }
        }
    }
    /**
     * 输出程序运行结果
     */
    public int[] ReportResult(){
        System.out.println("最优路径长度是"+bestLength);
        for(int a : bestTour) {
            System.out.println(a+",");
        }

        return bestTour;
    }
}
